import { Stage, Ticker, Graphics, Shape, Container, Bitmap } from "@createjs/easeljs";
import EventEmitter2  from "eventemitter2";
import { ROSLIB }  from "./RosLib";

var ROS2D = ROS2D || {
    REVISION : '0.10.0'
};

Stage.prototype.globalToRos = function(x, y) {
    var rosX = (x - this.x) / this.scaleX;
    var rosY = (this.y - y) / this.scaleY;
    return new ROSLIB.Vector3({
      x : rosX,
      y : rosY
    });
}

Stage.prototype.rosToGlobal = function(pos) {
    var x = pos.x * this.scaleX + this.x;
    var y = pos.y * this.scaleY + this.y;
    return {
      x : x,
      y : y
    };
};

Stage.prototype.rosQuaternionToGlobalTheta = function(orientation) {
    // See https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Rotation_matrices
    // here we use [x y z] = R * [1 0 0]
    var q0 = orientation.w;
    var q1 = orientation.x;
    var q2 = orientation.y;
    var q3 = orientation.z;
    // Canvas rotation is clock wise and in degrees
    return -Math.atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3)) * 180.0 / Math.PI;
};

ROS2D.Viewer = function(options) {
    var that = this;
    options = options || {};
    var divID = options.divID;
    this.width = options.width;
    this.height = options.height;
    var background = options.background || '#7f7f7f';

    // create the canvas to render to
    var canvas = document.createElement('canvas');
    canvas.width = this.width;
    canvas.height = this.height;
    canvas.style.background = background;
    document.getElementById(divID).appendChild(canvas);
    // create the easel to use
    this.scene = new Stage(canvas);

    // change Y axis center
    this.scene.y = this.height;

    // add the renderer to the page
    document.getElementById(divID).appendChild(canvas);

     // update at 30fps
    Ticker.framerate = 30;
    Ticker.addEventListener('tick', this.scene);
}

ROS2D.Viewer.prototype.addObject = function(object) {
    this.scene.addChild(object);
};

ROS2D.Viewer.prototype.scaleToDimensions = function(width, height) {
    // restore to values before shifting, if ocurred
    this.scene.x = typeof this.scene.x_prev_shift !== 'undefined' ? this.scene.x_prev_shift : this.scene.x;
    this.scene.y = typeof this.scene.y_prev_shift !== 'undefined' ? this.scene.y_prev_shift : this.scene.y;
  
    // save scene scaling
    this.scene.scaleX = this.width / width;
    this.scene.scaleY = this.height / height;
}; 

ROS2D.Viewer.prototype.shift = function(x, y) {
    // save current offset
    this.scene.x_prev_shift = this.scene.x;
    this.scene.y_prev_shift = this.scene.y;
  
    // shift scene by scaling the desired offset
    this.scene.x -= (x * this.scene.scaleX);
    this.scene.y += (y * this.scene.scaleY);
};

ROS2D.NavigationArrow = function(options) {
    var that = this;
    options = options || {};
    var size = options.size || 10;
    var strokeSize = options.strokeSize || 3;
    var strokeColor = options.strokeColor || Graphics.getRGB(0, 0, 0);
    var fillColor = options.fillColor || Graphics.getRGB(255, 0, 0);
    var pulse = options.pulse;
  
    // draw the arrow
    var graphics = new Graphics();
    // line width
    graphics.setStrokeStyle(strokeSize);
    graphics.beginStroke(strokeColor);
    graphics.beginFill(fillColor);
    graphics.moveTo(-size / 2.0, -size / 2.0);
    graphics.lineTo(size, 0);
    graphics.lineTo(-size / 2.0, size / 2.0);
    graphics.closePath();
    graphics.endFill();
    graphics.endStroke();

    // create the shape
    // Shape.call(this, graphics);
    var arrow = new Shape(graphics);
  
    // check if we are pulsing
    if (pulse) {
      // have the model "pulse"
      var growCount = 0;
      var growing = true;
      Ticker.addEventListener('tick', function() {
        if (growing) {
          arrow.scaleX *= 1.035;
          arrow.scaleY *= 1.035;
          growing = (++growCount < 10);
        } else {
          arrow.scaleX /= 1.035;
          arrow.scaleY /= 1.035;
          growing = (--growCount < 0);
        }
      });
    }
    return arrow;
};

ROS2D.NavigationArrow.prototype.__proto__ = Shape.prototype;

ROS2D.Grid = function(options) {
    var that = this;
    options = options || {};
    var size = options.size || 10;
    var cellSize = options.cellSize || 0.1;
    var lineWidth = options.lineWidth || 0.001;
    // draw the arrow
    var graphics = new Graphics();
    // line width
    graphics.setStrokeStyle(lineWidth*5);
    graphics.beginStroke(Graphics.getRGB(0, 0, 0));
    graphics.beginFill(Graphics.getRGB(255, 0, 0));
    graphics.moveTo(-size*cellSize, 0);
    graphics.lineTo(size*cellSize, 0);
    graphics.moveTo(0, -size*cellSize);
    graphics.lineTo(0, size*cellSize);
    graphics.endFill();
    graphics.endStroke();

    graphics.setStrokeStyle(lineWidth);
    graphics.beginStroke(Graphics.getRGB(0, 0, 0));
    graphics.beginFill(Graphics.getRGB(255, 0, 0));
    for (var i = -size; i <= size; i++) {
        graphics.moveTo(-size*cellSize, i * cellSize);
        graphics.lineTo(size*cellSize, i * cellSize);
        graphics.moveTo(i * cellSize, -size*cellSize);
        graphics.lineTo(i * cellSize, size*cellSize);
    }
    graphics.endFill();
    graphics.endStroke();
    // create the shape
    // Shape.call(this, graphics);
    var grid = new Shape(graphics);
    return grid;
};
ROS2D.Grid.prototype.__proto__ = Shape.prototype;

ROS2D.ImageMap = function(options) {
    options = options || {};
    var message = options.message;
    var image = options.image;

    var map = new Bitmap(image);
    map.image.onload = function() {
        var s = map.hitArea = new Shape();
        // s.graphics.fill("red").drawRect(0,0,map.image.width,map.image.height);
    }
    // save the metadata we need
    map.pose = new ROSLIB.Pose({
        position : message.origin.position,
        orientation : message.origin.orientation
    });

    // set the size
    map.width = message.width;
    map.height = message.height;

    // change Y direction
    map.y = -map.height * message.resolution;

    // // scale the image
    map.scaleX = message.resolution;
    map.scaleY = message.resolution;
    map.width *= map.scaleX;
    map.height *= map.scaleY;

    // // set the pose
    map.x += message.origin.position.x;
    map.y -= message.origin.position.y;

    return map;
};
ROS2D.ImageMap.prototype.__proto__ = Bitmap.prototype;

ROS2D.ImageMapClientWithMessage = function(options) {
    var that = this;
    options = options || {};
    var message = options.message;
    this.image = options.image;
    this.rootObject = options.rootObject || new Container();

    // create an empty shape to start with
    this.currentImage = new Shape();

    // create the image
    this.currentImage = new ROS2D.ImageMap({
        message : message,
        image : this.image
    });
    that.rootObject.addChild(this.currentImage);
    that.rootObject.addChild(new ROS2D.Grid({size:1}));

    setTimeout(function() {
        that.emit('change');
    }, 0);
}

ROS2D.ImageMapClientWithMessage.prototype.__proto__ = EventEmitter2.prototype;

ROS2D.ArrowShape = function(options) {
	var that = this;
	options = options || {};
	var size = options.size || 10;
	var strokeSize = options.strokeSize || 3;
	var strokeColor = options.strokeColor || Graphics.getRGB(0, 0, 0);
	var fillColor = options.fillColor || Graphics.getRGB(255, 0, 0);
	var pulse = options.pulse;

	// draw the arrow
	var graphics = new Graphics();

	var headLen = size / 3.0;
	var headWidth = headLen * 2.0 / 3.0;

	graphics.setStrokeStyle(strokeSize);
	graphics.beginStroke(strokeColor);
	graphics.moveTo(0, 0);
	graphics.lineTo(size-headLen, 0);

	graphics.beginFill(fillColor);
	graphics.moveTo(size, 0);
	graphics.lineTo(size-headLen, headWidth / 2.0);
	graphics.lineTo(size-headLen, -headWidth / 2.0);
	graphics.closePath();
	graphics.endFill();
	graphics.endStroke();

	// create the shape
	var arrowShape = new Shape(graphics);

	// check if we are pulsing
	if (pulse) {
		// have the model "pulse"
		var growCount = 0;
		var growing = true;
		Ticker.addEventListener('tick', function() {
			if (growing) {
				arrowShape.scaleX *= 1.035;
				arrowShape.scaleY *= 1.035;
				growing = (++growCount < 10);
			} else {
				arrowShape.scaleX /= 1.035;
				arrowShape.scaleY /= 1.035;
				growing = (--growCount < 0);
			}
		});
	}
    return arrowShape;
};
ROS2D.ArrowShape.prototype.__proto__ = Shape.prototype;

export { ROS2D }